﻿#include "socket_datasource.h"
#include <memory.h>
#include "../log/logger.h"

SocketDataSourceTool::SocketDataSourceTool()
{

}

SocketDataSourceTool::SocketDataSourceTool(int tcpPort, const char* peername)
{
    Connect(tcpPort,peername);
}
SocketDataSourceTool::~SocketDataSourceTool()
{
	this->Close();
}
bool SocketDataSourceTool::IsEof()
{
    return true;// meof;
}
#ifdef __QT_ENV_US__
void SocketDataSourceTool::Send(const char *message, int count)
{
	int ret = msk->write(message, count);
	msk->flush();
}

int SocketDataSourceTool::FetchNext(char *buf, int bufsize)
{
	if (msk->waitForReadyRead(-1) == false)
	{
		meof = true;
		return -1;
	}
	int ret = msk->read(buf, bufsize);
	return ret;
}

void SocketDataSourceTool::Close()
{
	msk->close();
}

bool SocketDataSourceTool::Connect(int tcpPort, const char* peername)
{
	return false;
}
bool SocketDataSourceTool::initial(int tcpPort, const char* peername)
{
	msk = new QTcpSocket();
	try
	{
		msk->connectToHost(peername, tcpPort, QTcpSocket::ReadWrite);
		if (msk->waitForConnected() == false)
		{
			LOG(LERROR) << "网口打开失败：" << peername << ":" << tcpPort << std::endl;
			meof = true;
		}
		else
		{
			LOG(INFO) << "网口打开成功：" << peername << ":" << tcpPort << std::endl;
		}

	}
	catch (std::exception e)
	{
		LOG(LERROR) << "网口打开失败：" << peername << ":" << tcpPort << ":" << e.what() << std::endl;
		meof = true;
		return false;
	}
	return true;
}
#elif defined(Q_OS_LINUX)

bool SocketDataSourceTool::Connect(int tcpPort, const char* peername)
{
	///定义sockaddr_in
	sock_client = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(tcpPort);  ///服务器端口
	servaddr.sin_addr.s_addr = inet_addr(peername);  ///服务器ip
	unsigned long ul = 1;
	ioctl(sock_client, FIONBIO, &ul); //设置为非阻塞模式
	int ret = connect(sock_client, (struct sockaddr *)&servaddr, sizeof(servaddr));
	//连接服务器，成功返回0，错误返回-1
	if (ret < 0)
	{
		LOG(LERROR) << "connect socket faild:ip-" << peername << ",port-" << tcpPort << std::endl;
		TRACE("connect socket faild:%d,ip-%s,port-%d\n", errno, peername, tcpPort);
		close(sock_client);
		sock_client = -1;
		return false;
	}
	else
	{
		LOG(INFO) << "网口打开成功：" << peername << ":" << tcpPort << std::endl;
	}
	return true;
}
int SocketDataSourceTool::FetchNext(char *buf, int bufsize)
{
	return recv(sock_client, buf, bufsize, 0); ///接收
}

void SocketDataSourceTool::Close()
{
	close(sock_client);
}
void SocketDataSourceTool::Send(const char *message, int count)
{
	if (sock_client > 0)
	{
		send(sock_client, message, count, 0); ///发送
	}
}

bool SocketDataSourceTool::isConnect()
{
//    if (sock_client == INVALID_SOCKET) return false;

//    struct timeval timeout;
//    timeout.tv_sec = 0;
//    timeout.tv_usec = 0;
//    fd_set fdwrite;
//    fd_set fdread;
//    FD_ZERO(&fdwrite);
//    FD_ZERO(&fdread);
//    FD_SET(sock_client, &fdwrite);
//    FD_SET(sock_client, &fdread);
//    int ret = select(sock_client + 1, &fdread, &fdwrite, NULL, &timeout);
//    if (ret == -1)
//        return false;

//    if (ret > 0)
//    {
//        if (FD_ISSET(clientSocket, &fdread))
//            return false;
//        else if (FD_ISSET(clientSocket, &fdwrite))
//        {
//            int err = 0;
//            int len = sizeof(err);
//            int result = getsockopt(clientSocket, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
//            if (result < 0 || err != 0)
//                return false;
//            return true;
//        }
//    }
    return false;
}
#elif WIN32
bool SocketDataSourceTool::Connect(int tcpPort, const char* peername)
{
	//加载套接字库
	WSADATA wsaData;
	int iRet = 0;
	iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iRet != 0)
	{
		LOG(LERROR) << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed!" << std::endl;
		return false;
	}
	if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
	{
		WSACleanup();
		LOG(LERROR) << "WSADATA version is not correct!" << std::endl;
		return false;
	}

	//创建套接字
	sock_client = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_client == INVALID_SOCKET)
	{
		LOG(LERROR) << "clientSocket = socket(AF_INET, SOCK_STREAM, 0) execute failed!" << std::endl;
		Close();
		return false;
	}
	int nNetTimeout = 3000;//3秒，//设置发送超时
	setsockopt(sock_client, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
	//初始化服务器端地址族变量
	SOCKADDR_IN srvAddr;
	srvAddr.sin_addr.S_un.S_addr = inet_addr(peername);
	srvAddr.sin_family = AF_INET;
	srvAddr.sin_port = htons(tcpPort);

	//连接服务器
	iRet = connect(sock_client, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR));
	if (0 != iRet)
	{
		LOG(LERROR) << "connect(clientSocket, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR)) execute failed!" << std::endl;
		return false;
	}
	LOG(INFO) << "网口打开成功：" << peername << ":" << tcpPort << std::endl;
	return true;
}
int SocketDataSourceTool::FetchNext(char *buf, int bufsize)
{
	int res = recv(sock_client, buf, bufsize, 0);
	// printf("%s\n", buf);
	return res;
}

void SocketDataSourceTool::Close()
{
	//清理
	closesocket(sock_client);
	WSACleanup();
}
void SocketDataSourceTool::Send(const char *message, int count)
{
	int ret = send(sock_client, message, count, 0);
	switch (ret)
	{
		case SOCKET_ERROR:
		{
			LOG(LERROR) << "send Error" << WSAGetLastError();
			break;
		}
		default:
		{
			if (ret != count)
			{
				LOG(LERROR) << "send Error,length dot equal.";
			}
			break;
		}
	}
}
bool SocketDataSourceTool::isConnect()
{
    if (sock_client == INVALID_SOCKET) return false;

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;
    fd_set fdwrite;
    fd_set fdread;
    FD_ZERO(&fdwrite);
    FD_ZERO(&fdread);
    FD_SET(sock_client, &fdwrite);
    FD_SET(sock_client, &fdread);
    int ret = select(sock_client + 1, &fdread, &fdwrite, NULL, &timeout);
    if (ret == -1)
        return false;

    if (ret > 0)
    {
        if (FD_ISSET(sock_client, &fdread))
            return false;
        else if (FD_ISSET(sock_client, &fdwrite))
        {
            int err = 0;
            int len = sizeof(err);
            int result = getsockopt(sock_client, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
            if (result < 0 || err != 0)
                return false;
            return true;
        }
    }
    return false;
}
#endif
